package com.ruoyi.common.utils.date;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class TimeUtil {
	private static final Logger LOGGER = LoggerFactory.getLogger(TimeUtil.class);
	public static final int PRECISION = 4;
	public static final int DEFAULT_INTERVAL_MINUTES = 15;
	public static final int DEFAULT_INTERVAL_HOURS = 1;

	public static final String DEFAULT_START_TIME = "06:00:00";
	public static final String DEFAULT_END_TIME = "22:00:00";

	public static enum EnumTimeUnit {
		SECONDS(0), MINUTES(1), HOURS(2), DAYS(3), WEEKS(4), MONTHS(5), QUARTER(6), YEARS(7);
		private int value = 0;

		private EnumTimeUnit(int value) {
			this.value = value;
		}

		public int getValue() {
			return value;
		}

		public static EnumTimeUnit getEnumBy(int value) {
			EnumTimeUnit[] enumTimeUnits = EnumTimeUnit.values();
			for (EnumTimeUnit enumTimeUnit : enumTimeUnits) {
				if (enumTimeUnit.value == value) {
					return enumTimeUnit;
				}
			}
			return null;
		}

		public static EnumTimeUnit getEnumBy(String str) {
			EnumTimeUnit[] enumTimeUnits = EnumTimeUnit.values();
			for (EnumTimeUnit enumTimeUnit : enumTimeUnits) {
				if (StringUtils.equals(String.valueOf(enumTimeUnit.value), str)
						|| StringUtils.equals(enumTimeUnit.name(), str)) {
					return enumTimeUnit;
				}
			}
			return null;
		}
	}

	private TimeUtil() {
	}

	public static Date asDate(LocalDate localDate) {
		return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
	}

	public static Date asDate(LocalDateTime localDateTime) {
		return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
	}

	public static LocalDate asLocalDate(Date date) {
		return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
	}

	public static LocalDateTime asLocalDateTime(Date date) {
		return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
	}

	public static long randomExpire(long seed) {
		Random random = new Random(seed);
		int res = random.nextInt(1000);
		return Long.valueOf(res).longValue();
	}

	public static boolean isValidDate(String date) {
		try {
			if (StringUtils.isBlank(date)) {
				return false;
			}
			date = StringUtils.trimToEmpty(date);
			Date time = TimeUtil.parseDate(date);
			if (time == null) {
				time = TimeUtil.parseTime(date);
			}
			return time != null;
		} catch (Throwable th) {
			LOGGER.error("TimeUtil.isValidDate() throwable", th);
		}
		return false;
	}

	public static boolean isValidTime(String date) {
		try {
			if (StringUtils.isBlank(date)) {
				return false;
			}
			date = StringUtils.trimToEmpty(date);
			Date time = TimeUtil.parseTime(date);
			return time != null;
		} catch (Throwable th) {
			LOGGER.error("TimeUtil.isValidDate() throwable", th);
		}
		return false;
	}

	public static String formatHHmm(String time) {
		Pattern pattern = Pattern.compile("(0[0-9]:[0-5][0-9])|(1[0-9]:[0-5][0-9])|(2[0-3]:[0-5][0-9])");
		if (pattern.matcher(time).matches()) {
			return String.format("%s:00", time);
		}
		if (matchTime(time)) {
			return time;
		}
		return null;
	}

	/**
	 * 判断时间格式是否为HH:mm:ss
	 * 
	 * @param time
	 * @return
	 */
	public static boolean matchTime(String time) {
		Pattern pattern = Pattern.compile(
				"(0[0-9]:[0-5][0-9]:[0-5][0-9])|(1[0-9]:[0-5][0-9]:[0-5][0-9])|(2[0-3]:[0-5][0-9]:[0-5][0-9])");
		boolean flag = pattern.matcher(time).matches();
		return flag;
	}

	/**
	 * 日期是否为今年
	 * 
	 * @param date
	 * @return
	 */
	public static boolean isCurrentYear(String date) {
		try {
			if (!isValidDate(date)) {
				return false;
			}
			date = StringUtils.trimToEmpty(date);
			Date time = TimeUtil.parseDate(date);
			if (time == null) {
				time = TimeUtil.parseTime(date);
			}
			Calendar timeCalendar = Calendar.getInstance(Locale.CHINA);
			timeCalendar.setTime(time);
			Calendar calendar = Calendar.getInstance(Locale.CHINA);
			return calendar.get(Calendar.YEAR) == timeCalendar.get(Calendar.YEAR);
		} catch (Throwable th) {
			LOGGER.error("TimeUtil.isCurrentYear() throwable", th);
		}
		return false;
	}

	public static boolean isCurrentYear(Date date) {
		return StringUtils.equals(TimeUtil.format(Calendar.getInstance(Locale.CHINA).getTime(), "yyyy"),
				TimeUtil.format(date, "yyyy"));
	}

	public static boolean isCurrentMonth(Date date) {
		return StringUtils.equals(TimeUtil.format(Calendar.getInstance(Locale.CHINA).getTime(), "yyyy-MM"),
				TimeUtil.format(date, "yyyy-MM"));
	}

	public static boolean isCurrentDate(Date date) {
		return StringUtils.equals(TimeUtil.format(Calendar.getInstance(Locale.CHINA).getTime(), "yyyy-MM-dd"),
				TimeUtil.format(date, "yyyy-MM-dd"));
	}

	public static Date parseLong(long timeInMillis) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTimeInMillis(timeInMillis);
		Date date = calendar.getTime();
		LOGGER.info("timeInMillis={}", TimeUtil.format(date, "yyyy-MM-dd'T'HH:mm:ss'Z'"));
		return date;
	}

	public static Date addYear(Date date, int n) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.YEAR, n);
		Date resultDate = calendar.getTime();
		return resultDate;
	}

	/**
	 * author 李成训 日期加减月份，
	 * 
	 * @param date
	 *            日期
	 * @param n
	 *            正数为加，负数为减
	 * @return
	 */
	public static Date addMonth(Date date, int n) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.MONTH, n);
		Date resultDate = calendar.getTime();
		return resultDate;
	}

	/**
	 * author 李成训 日期加减小时，
	 * 
	 * @param date
	 *            日期
	 * @param n
	 *            正数为加，负数为减
	 * @return
	 */
	public static Date addHour(Date date, int n) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.HOUR, n);
		Date resultDate = calendar.getTime();
		return resultDate;
	}

	/**
	 * author 李成训 日期加减-周，
	 * 
	 * @param date
	 *            日期
	 * @param n
	 *            正数为加，负数为减
	 * @return
	 */
	public static Date addWeek(Date date, int n) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.WEEK_OF_YEAR, n);
		Date resultDate = calendar.getTime();
		return resultDate;
	}

	/**
	 * author 李成训 日期加减日，
	 * 
	 * @param date
	 *            日期
	 * @param n
	 *            正数为加，负数为减
	 * @return
	 */
	public static Date addDay(Date date, int n) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.DATE, n);
		Date resultDate = calendar.getTime();
		return resultDate;
	}

	/**
	 * author 李成训 日期加减,分总，
	 * 
	 * @param date
	 *            日期
	 * @param n
	 *            正数为加，负数为减
	 * @return
	 */
	public static Date addMinute(Date date, int n) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.MINUTE, n);
		Date resultDate = calendar.getTime();
		return resultDate;
	}

	/**
	 * 解析时间
	 * 
	 * @param time
	 * @return
	 */
	public static Date parseTime(String time) {
		if (StringUtils.isBlank(time)) {
			return null;
		}
		Date resDate = null;
		DateFormat dateFormat = null;
		try {
			time = StringUtils.trimToEmpty(time);
			if (NumberUtils.isDigits(time)) {
				Calendar calendar = Calendar.getInstance();
				calendar.setTimeInMillis(Long.valueOf(time));
				return calendar.getTime();
			}
			dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss+0800");
			resDate = dateFormat.parse(time);
		} catch (Throwable th) {
			try {
				dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
				resDate = dateFormat.parse(time);
			} catch (Throwable thz) {
				try {
					dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
					resDate = dateFormat.parse(time);
				} catch (Throwable thr) {
					try {
						dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
						resDate = dateFormat.parse(time);
					} catch (Throwable ex) {
						try {
							dateFormat = new SimpleDateFormat("dd/MM,yyyy HH:mm:ss");
							resDate = dateFormat.parse(time);
						} catch (Throwable eth) {
						}
					}
				}
			}
		}
		return resDate;
	}

	/**
	 * 将String格式的日期转换成指定的日期格式
	 *
	 * @param time
	 * @return
	 */
	public static Date parseTime(String time, String pattern) {
		if (StringUtils.isBlank(time)) {
			LOGGER.error("传入日期时间戳为空 time : {}", time);
			return null;
		}
		Date resDate = null;
		DateFormat dateFormat = new SimpleDateFormat(pattern);
		try {
			time = StringUtils.trimToEmpty(time);
			resDate = dateFormat.parse(time);
		} catch (Throwable th) {
			LOGGER.error("format date fail : {}", th);
		}
		return resDate;
	}

	/**
	 * 解析日期
	 * 
	 * @param date
	 * @return
	 */
	public static Date parseDate(String date) {
		if (StringUtils.isBlank(date)) {
			return null;
		}
		Date resDate = null;
		DateFormat dateFormat = null;
		try {
			date = StringUtils.trimToEmpty(date);
			dateFormat = new SimpleDateFormat("yyyy-MM-dd");
			resDate = dateFormat.parse(date);
		} catch (Throwable th) {
			try {
				dateFormat = new SimpleDateFormat("yyyy/MM/dd");
				resDate = dateFormat.parse(date);
			} catch (Throwable ex) {
				try {
					dateFormat = new SimpleDateFormat("dd/MM,yyyy");
					resDate = dateFormat.parse(date);
				} catch (Throwable eth) {
				}
			}
		}
		return resDate;
	}

	public static Date getYesterday() {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.add(Calendar.DATE, -1);
		return calendar.getTime();
	}

	public static Date getYesterday(int hour, int minutes, int seconds) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.add(Calendar.DATE, -1);
		calendar.set(Calendar.HOUR_OF_DAY, hour);
		calendar.set(Calendar.MINUTE, minutes);
		calendar.set(Calendar.SECOND, seconds);
		return calendar.getTime();
	}

	public static Date getYesterday(Date date, int hour, int minutes, int seconds) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.add(Calendar.DATE, -1);
		calendar.set(Calendar.HOUR_OF_DAY, hour);
		calendar.set(Calendar.MINUTE, minutes);
		calendar.set(Calendar.SECOND, seconds);
		return calendar.getTime();
	}

	public static Date getCurrentDate() {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		return calendar.getTime();
	}

	public static int getCurrentMonth() {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		return calendar.get(Calendar.MONTH) + 1;
	}

	public static int getCurrentYear() {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		return calendar.get(Calendar.YEAR);
	}

	/**
	 * 获取指定日期的年份
	 * 
	 * @param date
	 * @return
	 */
	public static int getDateYear(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		return calendar.get(Calendar.YEAR);
	}

	public static int getDateMonth(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		return calendar.get(Calendar.MONTH) + 1;
	}

	/**
	 * 获取指定原始日期的前一天日期
	 * 
	 * @param date
	 * @return
	 */
	public static Date getStartTimeOfYesterday(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) - 1);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		return calendar.getTime();
	}

	/**
	 * 
	 * @param date
	 * @return
	 */
	public static Date getEndTimeOfYesterday(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) - 1);
		calendar.set(Calendar.HOUR_OF_DAY, 23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		calendar.set(Calendar.MILLISECOND, 999);
		return calendar.getTime();
	}

	public static Date getStartTimeBeforeDay(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) - 1);
		return calendar.getTime();
	}

	public static Date getStartTimeOfHour(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		int hour = calendar.get(Calendar.HOUR_OF_DAY);
		int minutes = calendar.get(Calendar.MINUTE);
		int seconds = calendar.get(Calendar.SECOND);
		if (minutes == 0 && seconds == 0) {
			calendar.set(Calendar.HOUR_OF_DAY, hour - 1);
		}
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		Date startDate = calendar.getTime();
		return startDate;
	}

	public static Date getEndTimeOfHour(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		int hour = calendar.get(Calendar.HOUR_OF_DAY);
		int minutes = calendar.get(Calendar.MINUTE);
		int seconds = calendar.get(Calendar.SECOND);
		if (minutes == 0 && seconds == 0) {
			calendar.set(Calendar.HOUR_OF_DAY, hour - 1);
		}
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		Date startDate = calendar.getTime();
		return startDate;
	}

	/**
	 * 获取指定日期的 00:00:00 的日期对象
	 * 
	 * @param date
	 * @return
	 */
	public static Date getStartTimeOfDay(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		return calendar.getTime();
	}

	/**
	 * 获取指定日期的 23:59:59.999的日期对象
	 * 
	 * @param date
	 * @return
	 */
	public static Date getEndTimeOfDay(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.HOUR_OF_DAY, 23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		calendar.set(Calendar.MILLISECOND, 999);
		return calendar.getTime();
	}

	/**
	 * 获取指定日期一个月前的日期
	 * 
	 * @param date
	 * @return
	 */
	public static Date getStartTimeBeforeMonth(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 1);
		return calendar.getTime();
	}

	/**
	 * 获取指定日期当月的起始时间
	 * 
	 * @param date
	 * @return
	 */
	public static Date getStartTimeOfMonth(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		return calendar.getTime();
	}

	/**
	 * 获取指定日期当月的结束时间
	 * 
	 * @param date
	 * @return
	 */
	public static Date getEndTimeOfMonth(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) + 1);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.HOUR_OF_DAY, 23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		calendar.set(Calendar.MILLISECOND, 999);
		calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) - 1);
		return calendar.getTime();
	}

	/**
	 * 获取上一月的起始日期
	 * 
	 * @param date
	 * @return
	 */
	public static Date getStartTimeOfPreviousMonth(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 1);
		Date start = TimeUtil.getStartTimeOfMonth(calendar.getTime());
		return start;
	}

	/**
	 * 获取上一月的截止日期
	 * 
	 * @param date
	 * @return
	 */
	public static Date getEndTimeOfPreviousMonth(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 1);
		Date end = TimeUtil.getEndTimeOfMonth(calendar.getTime());
		return end;
	}

	/**
	 * 获取当前日期所属季度的第一天
	 * 
	 * @param date
	 * @return
	 */
	public static Date getStartTimeOfSeason(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		int month = calendar.get(Calendar.MONTH);
		int season = Double.valueOf(Math.ceil((month + 1) * 1.0 / 3)).intValue();
		int firstMonth = Double.valueOf(3 * (season - 1)).intValue();
		calendar.set(Calendar.MONTH, firstMonth);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		Date startDate = calendar.getTime();
		return startDate;
	}

	/**
	 * 获取当前日期所属季度的最后一天
	 * 
	 * @param date
	 * @return
	 */
	public static Date getEndTimeOfSeason(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		int month = calendar.get(Calendar.MONTH);
		int season = Double.valueOf(Math.ceil((month + 1) * 1.0 / 3)).intValue();
		int lastMonth = Integer.valueOf(3 * season).intValue();
		calendar.set(Calendar.MONTH, lastMonth - 1);
		Date lastDate = calendar.getTime();
		Date endDate = TimeUtil.getLastDateOfMonth(lastDate);
		return endDate;
	}

	/**
	 * 获取前一季度的起始日期
	 * 
	 * @param date
	 * @return
	 */
	public static Date getStartTimeOfPreviousSeason(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 3);
		Date startDate = TimeUtil.getStartTimeOfSeason(calendar.getTime());
		return startDate;
	}

	/**
	 * 获取前一季度的截止日期
	 * 
	 * @param date
	 * @return
	 */
	public static Date getEndTimeOfPreviousSeason(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 3);
		Date endDate = TimeUtil.getEndTimeOfSeason(calendar.getTime());
		return endDate;
	}

	/**
	 * 获取当年的第一天
	 * 
	 * @param date
	 * @return
	 */
	public static Date getStartTimeOfYear(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.MONTH, 0);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		return calendar.getTime();
	}

	/**
	 * 获取当年的最后一天
	 * 
	 * @param date
	 * @return
	 */
	public static Date getEndTimeOfYear(Date date) {
		Date lastDate = TimeUtil.getLastDateOfYear(date);
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(lastDate);
		calendar.set(Calendar.HOUR_OF_DAY, 23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		calendar.set(Calendar.MILLISECOND, 999);
		return calendar.getTime();
	}

	/**
	 * 获取某年第一天日期
	 *
	 * @param year
	 *            年份
	 * @return Date
	 */
	public static Date getYearFirst(int year) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.clear();
		calendar.set(Calendar.YEAR, year);
		calendar.set(Calendar.MONTH, 0);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		Date currYearFirst = calendar.getTime();
		return currYearFirst;
	}

	/**
	 * 获取某年最后一天日期
	 *
	 * @param year
	 *            年份
	 * @return Date
	 */
	public static Date getYearLast(int year) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.clear();
		calendar.set(Calendar.YEAR, year);
		calendar.roll(Calendar.DAY_OF_YEAR, -1);
		calendar.set(Calendar.MONTH, 11);
		calendar.set(Calendar.DAY_OF_MONTH, 31);
		calendar.set(Calendar.HOUR_OF_DAY, 23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		calendar.set(Calendar.MILLISECOND, 999);
		Date currYearLast = calendar.getTime();

		return currYearLast;
	}

	/**
	 * 获取上一年度的起始时间
	 * 
	 * @param date
	 * @return
	 */
	public static Date getStartTimeOfPreviousYear(Date date) {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) - 1);
		Date startDate = TimeUtil.getStartTimeOfYear(calendar.getTime());
		return startDate;
	}

	/**
	 * 获取上一年度的截止时间
	 * 
	 * @param date
	 * @return
	 */
	public static Date getEndTimeOfPreviousYear(Date date) {
		Date lastDate = TimeUtil.getLastDateOfYear(date);
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(lastDate);
		calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) - 1);
		Date endDate = TimeUtil.getEndTimeOfYear(calendar.getTime());
		return endDate;
	}

	/**
	 * 获取历史起始时间 1970-01-01
	 * 
	 * @return
	 */
	public static Date getStartTimeOfHistory() {
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.set(Calendar.YEAR, 1970);
		calendar.set(Calendar.MONTH, 0);
		calendar.set(Calendar.DAY_OF_YEAR, 1);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		return calendar.getTime();
	}

	public static int getTimeField(String time, EnumTimeUnit timeUnit) {
		int result = -1;
		time = StringUtils.trimToEmpty(time).replaceAll("\\s+", " ");
		String regex = "(((\\d{4})\\-(\\d{1,2})\\-(\\d{1,2})))?(\\s+)?((\\d{1,2}):(\\d{1,2}):(\\d{1,2}))";
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(time);
		if (matcher.matches()) {
			// Calendar calendar = Calendar.getInstance(Locale.CHINA);
			switch (timeUnit) {
			case SECONDS:
				String seconds = time.replaceAll(regex, "$10");
				if (NumberUtils.isDigits(seconds)) {
					result = Integer.valueOf(seconds);
				}
				break;
			case MINUTES:
				String minutes = time.replaceAll(regex, "$9");
				if (NumberUtils.isDigits(minutes)) {
					result = Integer.valueOf(minutes);
				}
				break;
			case HOURS:
				String hours = time.replaceAll(regex, "$8");
				if (NumberUtils.isDigits(hours)) {
					result = Integer.valueOf(hours);
				}
				break;
			case DAYS:
				String days = time.replaceAll(regex, "$5");
				if (NumberUtils.isDigits(days)) {
					result = Integer.valueOf(days);
				}
				break;
			case MONTHS:
				String months = time.replaceAll(regex, "$4");
				if (NumberUtils.isDigits(months)) {
					result = Integer.valueOf(months);
				}
				break;
			case YEARS:
				String years = time.replaceAll(regex, "$3");
				if (NumberUtils.isDigits(years)) {
					result = Integer.valueOf(years);
				}
				break;
			default:
				break;
			}
		}
		return result;
	}

	/**
	 * 
	 * @param date
	 * @return TreeMap(quarter, Set(month))
	 */
	public static TreeMap<Integer, TreeSet<String>> getMonthsOfQuarters(Date date, String pattern) {
		TreeMap<Integer, TreeSet<String>> resMap = new TreeMap<>();
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		Date firstDate = TimeUtil.getYearFirst(calendar.get(Calendar.YEAR));
		Date latestDate = TimeUtil.getLastDateOfYear(date);
		for (int idx = firstDate.getMonth(); idx <= latestDate.getMonth(); idx++) {
			int month = (idx + 1);
			int quarter = Double.valueOf(Math.ceil(idx / 3)).intValue() + 1;
			TreeSet<String> months = Optional.ofNullable(resMap.get(quarter)).orElse(new TreeSet<>());
			Date resDate = TimeUtil
					.parseDate(String.format("%s-%s-01", TimeUtil.format(date, "yyyy"), String.format("%0,2d", month)));
			months.add(TimeUtil.format(resDate, pattern));
			resMap.put(quarter, months);
		}
		return resMap;
	}

	public static TreeMap<Integer, TreeSet<Integer>> getMonthsOfQuarters() {
		TreeMap<Integer, TreeSet<Integer>> resMap = new TreeMap<>();
		for (int idx = 0; idx < 12; idx++) {
			int month = (idx + 1);
			int quarter = Double.valueOf(Math.ceil(idx / 3)).intValue() + 1;
			TreeSet<Integer> months = Optional.ofNullable(resMap.get(quarter)).orElse(new TreeSet<>());
			months.add(month);
			resMap.put(quarter, months);
		}
		return resMap;
	}

	/**
	 * 获取指定日期所属年份的月度时段
	 * 
	 * @param date
	 * @return
	 */
	public static TreeMap<Integer, TimeDuration> getTimeDurationPerMonth(Date date) {
		TreeMap<Integer, TimeDuration> resMap = new TreeMap<>();
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		for (int idx = 0; idx < 12; idx++) {
			calendar.set(Calendar.MONTH, idx);
			int month = (idx + 1);
			Date start = TimeUtil.getStatisticStartTime(calendar.getTime(), EnumTimeUnit.MONTHS);
			Date end = TimeUtil.getStatisticEndTime(calendar.getTime(), EnumTimeUnit.MONTHS);
			TimeDuration timeDuration = new TimeDuration(start, end);
			resMap.put(month, timeDuration);
		}
		return resMap;
	}

	public static TreeMap<Integer, TimeDuration> getTimeDurationPerQuarter(Date date) {
		TreeMap<Integer, TimeDuration> resMap = new TreeMap<>();
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		TreeMap<Integer, TreeSet<Integer>> quarterMonthMap = TimeUtil.getMonthsOfQuarters();
		for (Map.Entry<Integer, TreeSet<Integer>> entry : quarterMonthMap.entrySet()) {
			int quarter = entry.getKey();
			TreeSet<Integer> months = entry.getValue();
			int startMonth = months.first() - 1;
			int endMonth = months.last() - 1;
			calendar.set(Calendar.MONTH, startMonth);
			Date start = TimeUtil.getStatisticStartTime(calendar.getTime(), EnumTimeUnit.MONTHS);
			calendar.set(Calendar.MONTH, endMonth);
			Date end = TimeUtil.getStatisticEndTime(calendar.getTime(), EnumTimeUnit.MONTHS);
			TimeDuration timeDuration = new TimeDuration(start, end);
			resMap.put(quarter, timeDuration);
		}
		return resMap;
	}

	/**
	 * 按指定模式格式化日期
	 * 
	 * @param date
	 *            日期值
	 * @return
	 */
	public static String format(Date date) {
		if (date == null) {
			return "";
		}
		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
		String result = dateFormat.format(date);
		return result;
	}

	/**
	 * 按指定模式格式化日期
	 * 
	 * @param date
	 *            日期值
	 * @param pattern
	 *            格式化模式
	 * @return
	 */
	public static String format(Date date, String pattern) {
		DateFormat dateFormat = null;
		try {
			if (date == null) {
				return "";
			}
			pattern = StringUtils.defaultIfBlank(StringUtils.trimToEmpty(pattern), "yyyy-MM-dd'T'HH:mm:ss'Z'");
			dateFormat = new SimpleDateFormat(pattern);
			String result = dateFormat.format(date);
			return result;
		} catch (Throwable th) {
			LOGGER.error("TimeUtil.format() throwable", th);
			dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
			return dateFormat.format(date);
		}
	}

	/**
	 * 获取日期顺序号(指定日期是一年内的第几天)
	 * 
	 * @param date
	 *            指定日期
	 * @return
	 */
	public static int getDateSN(Date date) {
		if (date == null) {
			throw new IllegalArgumentException("Invalid arguments");
		}
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.MONTH, 0);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		Date start = calendar.getTime();
		LOGGER.debug("TimeUtil.getDateSN() start={}", TimeUtil.format(start));
		calendar.setTime(date);
		calendar.set(Calendar.HOUR_OF_DAY, 23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		Date end = calendar.getTime();
		LOGGER.debug("TimeUtil.getDateSN() end={}", TimeUtil.format(end));
		double result = (end.getTime() - start.getTime()) / (24 * 3600 * 1000) + 1;
		LOGGER.debug("TimeUtil.getDateSN() result={}", result);
		return BigDecimal.valueOf(Math.ceil(result)).intValue();
	}

	/**
	 * 获取指定日期所属年份的最后一天日期
	 * 
	 * @param date
	 *            指定日期
	 * @return
	 */
	public static Date getLastDateOfYear(Date date) {
		if (date == null) {
			throw new IllegalArgumentException("Invalid arguments");
		}
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.MONTH, 11);
		calendar.set(Calendar.DAY_OF_MONTH, 31);
		calendar.set(Calendar.HOUR_OF_DAY, 23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		Date result = calendar.getTime();
		return result;
	}

	/**
	 * 获取指定日期所属月份的最后一天
	 *
	 * @param date
	 * @return
	 */
	public static Date getLastDateOfMonth(Date date) {
		if (date == null) {
			throw new IllegalArgumentException("Invalid arguments");
		}
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);

		Calendar lastCalendar = Calendar.getInstance();
		lastCalendar.setTime(date);
		int nIdx = 1;
		for (int idx = 1; idx <= 31; idx++) {
			lastCalendar.set(Calendar.DAY_OF_MONTH, idx);
			if (lastCalendar.get(Calendar.MONTH) > calendar.get(Calendar.MONTH)) {
				break;
			}
			nIdx = idx;
		}
		lastCalendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
		lastCalendar.set(Calendar.DAY_OF_MONTH, nIdx);
		lastCalendar.set(Calendar.HOUR_OF_DAY, 23);
		lastCalendar.set(Calendar.MINUTE, 59);
		lastCalendar.set(Calendar.SECOND, 59);
		Date result = lastCalendar.getTime();
		return result;
	}

	/**
	 * 计算日期间隔时间
	 * 
	 * @param start
	 *            起始时间
	 * @param end
	 *            结束时间
	 * @param timeUnit
	 *            间隔时间单位
	 * @return 时间间隔
	 */
	public static double getDuration(Date startDate, Date endDate, TimeUnit timeUnit) {
		if (startDate == null || endDate == null || timeUnit == null) {
			LOGGER.error("Invalid arguments. start or end or timeUnit is null");
			throw new IllegalArgumentException("Invalid arguments. start or end or timeUnit is null");
		}
		Date start = TimeUtil.min(startDate, endDate);
		Date end = TimeUtil.max(startDate, endDate);
		long duration = (end.getTime() - start.getTime());
		LOGGER.debug("TimeUtil.getDuration() duration={}", duration);
		Map<TimeUnit, Double> resMap = new HashMap<TimeUnit, Double>();
		resMap.put(TimeUnit.DAYS, 1000.0 * 3600 * 24);
		resMap.put(TimeUnit.HOURS, 1000.0 * 3600);
		resMap.put(TimeUnit.MINUTES, 1000.0 * 60);
		resMap.put(TimeUnit.SECONDS, 1000.0);
		BigDecimal durationVal = BigDecimal.valueOf(duration * 1.0).setScale(4, RoundingMode.HALF_UP);
		BigDecimal scale = BigDecimal.valueOf(resMap.get(timeUnit)).setScale(4, RoundingMode.HALF_UP);

		BigDecimal result = durationVal.divide(scale, 4, BigDecimal.ROUND_HALF_UP);
		double res = result.setScale(4, RoundingMode.HALF_UP).doubleValue();
		return res;
	}

	/**
	 * 按 startTime 到 endTime 的时段获取指定日期的时段对象
	 * 
	 * @param date
	 * @param startTime
	 * @param endTime
	 * @return
	 */
	public static TimeDuration getDuration(Date date, String startTime, String endTime) {
		startTime = TimeUtil.formatHHmm(startTime);
		endTime = TimeUtil.formatHHmm(endTime);
		if (TimeUtil.matchTime(startTime) && TimeUtil.matchTime(endTime)) {
			String currentDate = TimeUtil.format(date, "yyyy-MM-dd");
			Date startDate = TimeUtil.parseTime(String.format("%s %s", currentDate, startTime), "yyyy-MM-dd HH:mm:ss");
			Date endDate = TimeUtil.parseTime(String.format("%s %s", currentDate, endTime), "yyyy-MM-dd HH:mm:ss");
			TimeDuration timeDuration = new TimeDuration(startDate, endDate);
			return timeDuration;
		}
		return null;
	}

	/**
	 * 计算总的间隔时间
	 * 
	 * @param durationList
	 *            时段集合
	 * @param timeUnit
	 *            时间单位
	 * @return
	 */
	public static double getTotalDuration(List<TimeDuration> durationList, TimeUnit timeUnit) {
		double total = 0.0;
		durationList = Optional.ofNullable(durationList).orElse(Collections.EMPTY_LIST);
		for (TimeDuration timeDuration : durationList) {
			double duration = TimeUtil.getDuration(timeDuration.getStartDate(), timeDuration.getEndDate(), timeUnit);
			total += duration;
		}
		return BigDecimal.valueOf(total).setScale(TimeUtil.PRECISION, RoundingMode.HALF_UP).doubleValue();
	}

	/**
	 * 获取指定时间所属年份的天数
	 * 
	 * @param date
	 *            日期
	 * @return
	 */
	public static int getDaysOfYear(Date date) {
		Date lastDate = getLastDateOfYear(date);
		LOGGER.debug("TimeUtil.getDays() lastDate={}", TimeUtil.format(lastDate));
		int days = getDateSN(lastDate);
		LOGGER.debug("TimeUtil.getDays() days={}", days);
		return days;
	}

	/**
	 * 获取统计起始时间(interval分钟前)
	 * 
	 * @param interval
	 *            间隔时间(mins)
	 * @return
	 */
	public static Date getStatisticStartTimeMins(int interval) {
		Date startDate = null;
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		int minute = calendar.get(Calendar.MINUTE);
		calendar.set(Calendar.MINUTE, minute - interval);
		startDate = calendar.getTime();
		return startDate;
	}

	/**
	 * 获取统计起始时间(interval小时前)
	 * 
	 * @param interval
	 *            间隔时间(hours)
	 * @return
	 */
	public static Date getStatisticStartTimeHours(Date date, int interval) {
		Date startDate = TimeUtil.getStartTimeOfDay(date);
		Date endDate = TimeUtil.getEndTimeOfDay(date);
		TimeDuration specialDuration = new TimeDuration(startDate, endDate);
		List<TimeDuration> list = TimeUtil.splitDurationByInterval(specialDuration, interval, TimeUnit.HOURS);
		List<TimeDuration> resList = list.stream().filter(item -> item != null && item.inDuration(date.getTime()))
				.collect(Collectors.toList());
		TimeDuration duration = resList.get(0);
		return duration.getStartDate();
	}

	public static Date getStatisticEndTimeHours(Date date, int interval) {
		Date startDate = TimeUtil.getStartTimeOfDay(date);
		Date endDate = TimeUtil.getEndTimeOfDay(date);
		TimeDuration specialDuration = new TimeDuration(startDate, endDate);
		List<TimeDuration> list = TimeUtil.splitDurationByInterval(specialDuration, interval, TimeUnit.HOURS);
		List<TimeDuration> resList = list.stream().filter(item -> item != null && item.inDuration(date.getTime()))
				.collect(Collectors.toList());
		TimeDuration duration = resList.get(0);
		return duration.getEndDate();
	}

	/**
	 * 查询统计间隔起始时间
	 * 
	 * @param interval
	 * @return
	 */
	public static Date getStatisticStartTimeMinutes(Date date, int interval) {
		Date startDate = TimeUtil.getStartTimeOfDay(date);
		Date endDate = TimeUtil.getEndTimeOfDay(date);
		TimeDuration specialDuration = new TimeDuration(startDate, endDate);
		List<TimeDuration> list = TimeUtil.splitDurationByInterval(specialDuration, interval, TimeUnit.MINUTES);
		List<TimeDuration> resList = list.stream().filter(item -> item != null && item.inDuration(date.getTime()))
				.collect(Collectors.toList());
		TimeDuration duration = resList.get(0);
		return duration.getStartDate();
	}

	/**
	 * 查询统计间隔截止时间
	 * 
	 * @param date
	 * @param interval
	 * @return
	 */
	public static Date getStatisticEndTimeMinutes(Date date, int interval) {
		Date startDate = TimeUtil.getStartTimeOfDay(date);
		Date endDate = TimeUtil.getEndTimeOfDay(date);
		TimeDuration specialDuration = new TimeDuration(startDate, endDate);
		List<TimeDuration> list = TimeUtil.splitDurationByInterval(specialDuration, interval, TimeUnit.MINUTES);
		List<TimeDuration> resList = list.stream().filter(item -> item != null && item.inDuration(date.getTime()))
				.collect(Collectors.toList());
		TimeDuration duration = resList.get(0);
		return duration.getEndDate();
	}

	/**
	 * 获取统计起始时间
	 * 
	 * @param timeUnit
	 *            时间单位
	 * @return
	 */
	public static Date getStatisticStartTime(EnumTimeUnit timeUnit) {
		Date startDate = null;
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		switch (timeUnit) {
		case MINUTES:
			int minute = calendar.get(Calendar.MINUTE);
			calendar.set(Calendar.MINUTE, minute - DEFAULT_INTERVAL_MINUTES);
			calendar.set(Calendar.SECOND, 0);
			startDate = calendar.getTime();
			break;
		case HOURS:
			int hour = calendar.get(Calendar.HOUR_OF_DAY);
			int minutes = calendar.get(Calendar.MINUTE);
			if (minutes == 0) {
				calendar.set(Calendar.HOUR_OF_DAY, hour - 1);
			}
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			startDate = calendar.getTime();
			break;
		case DAYS:
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			startDate = calendar.getTime();
			break;
		case WEEKS:
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			startDate = calendar.getTime();
			break;
		case MONTHS:
			calendar.set(Calendar.DAY_OF_MONTH, 1);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			startDate = calendar.getTime();
			break;
		case QUARTER:
			int month = calendar.get(Calendar.MONTH);
			int season = Double.valueOf(Math.ceil((month + 1) * 1.0 / 3)).intValue();
			int firstMonth = Double.valueOf(3 * (season - 1)).intValue();
			calendar.set(Calendar.MONTH, firstMonth);
			calendar.set(Calendar.DAY_OF_MONTH, 1);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			startDate = calendar.getTime();
			break;
		case YEARS:
			calendar.set(Calendar.MONTH, 0);
			calendar.set(Calendar.DAY_OF_MONTH, 1);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			startDate = calendar.getTime();
			break;
		default:
			throw new IllegalArgumentException("Invalid timeunit");
		}
		return startDate;
	}

	/**
	 * 获取统计起始时间
	 * 
	 * @param endDate
	 *            截止时间
	 * @param timeUnit
	 *            时间单位
	 * @return
	 */
	public static Date getStatisticStartTime(Date endDate, EnumTimeUnit timeUnit) {
		Date startDate = null;
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(endDate);
		switch (timeUnit) {
		case MINUTES:
			int minute = calendar.get(Calendar.MINUTE);
			calendar.set(Calendar.MINUTE, minute - DEFAULT_INTERVAL_MINUTES);
			calendar.set(Calendar.SECOND, 0);
			startDate = calendar.getTime();
			break;
		case HOURS:
			int hour = calendar.get(Calendar.HOUR_OF_DAY);
			int minutes = calendar.get(Calendar.MINUTE);
			if (minutes == 0) {
				calendar.set(Calendar.HOUR_OF_DAY, hour - 1);
			}
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			startDate = calendar.getTime();
			break;
		case DAYS:
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			startDate = calendar.getTime();
			break;
		case WEEKS:
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			startDate = calendar.getTime();
			break;
		case MONTHS:
			calendar.set(Calendar.DAY_OF_MONTH, 1);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			startDate = calendar.getTime();
			break;
		case QUARTER:
			int month = calendar.get(Calendar.MONTH);
			int season = Double.valueOf(Math.ceil((month + 1) * 1.0 / 3)).intValue();
			int firstMonth = Double.valueOf(3 * (season - 1)).intValue();
			calendar.set(Calendar.MONTH, firstMonth);
			calendar.set(Calendar.DAY_OF_MONTH, 1);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			startDate = calendar.getTime();
			break;
		case YEARS:
			calendar.set(Calendar.MONTH, 0);
			calendar.set(Calendar.DAY_OF_MONTH, 1);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			startDate = calendar.getTime();
			break;
		default:
			throw new IllegalArgumentException("Invalid timeunit");
		}
		return startDate;
	}

	public static Date getStatisticEndTime(Date date, EnumTimeUnit timeUnit) {
		Date endDate = null;
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(date);
		switch (timeUnit) {
		case MINUTES:
			calendar.set(Calendar.SECOND, 59);
			endDate = calendar.getTime();
			break;
		case HOURS:
			int hour = calendar.get(Calendar.HOUR_OF_DAY);
			calendar.set(Calendar.HOUR_OF_DAY, hour);
			calendar.set(Calendar.MINUTE, 59);
			calendar.set(Calendar.SECOND, 59);
			endDate = calendar.getTime();
			break;
		case DAYS:
			calendar.set(Calendar.HOUR_OF_DAY, 23);
			calendar.set(Calendar.MINUTE, 59);
			calendar.set(Calendar.SECOND, 59);
			endDate = calendar.getTime();
			break;
		case WEEKS:
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
			calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) + 7);
			calendar.set(Calendar.HOUR_OF_DAY, 23);
			calendar.set(Calendar.MINUTE, 59);
			calendar.set(Calendar.SECOND, 59);
			endDate = calendar.getTime();
			break;
		case MONTHS:
			calendar.set(Calendar.HOUR_OF_DAY, 23);
			calendar.set(Calendar.MINUTE, 59);
			calendar.set(Calendar.SECOND, 59);
			endDate = TimeUtil.getLastDateOfMonth(calendar.getTime());
			break;
		case QUARTER:
			int month = calendar.get(Calendar.MONTH);
			int season = Double.valueOf(Math.ceil((month + 1) * 1.0 / 3)).intValue();
			int firstMonth = Double.valueOf(3 * (season - 1)).intValue();
			int lastMonth = Double.valueOf(3 * season).intValue() - 1;
			calendar.set(Calendar.MONTH, lastMonth);
			Date endOfQuarter = TimeUtil.getLastDateOfMonth(calendar.getTime());
			endDate = endOfQuarter;
			break;
		case YEARS:
			Date endOfYear = TimeUtil.getLastDateOfYear(date);
			endDate = endOfYear;
			break;
		default:
			throw new IllegalArgumentException("Invalid timeunit");
		}
		return endDate;
	}

	public static long getMillisSecondsBy(long intervals, TimeUnit timeUnit) {
		long result = 0L;
		switch (timeUnit) {
		case DAYS:
			result = intervals * 24 * 3600 * 1000;
			break;
		case HOURS:
			result = intervals * 3600 * 1000;
			break;
		case MINUTES:
			result = intervals * 60 * 1000;
			break;
		case SECONDS:
			result = intervals * 1000;
			break;
		case MILLISECONDS:
			result = intervals;
			break;
		case MICROSECONDS:
			result = Double.valueOf(intervals / 1000.0).longValue();
			break;
		case NANOSECONDS:
			result = Double.valueOf(intervals / (1000.0 * 1000.0)).longValue();
			break;
		default:
			result = Long.MIN_VALUE;
		}
		return result;
	}

	/**
	 * 比较日期取靠后的日期
	 * 
	 * @param self
	 *            日期1
	 * @param other
	 *            日期2
	 * @return
	 */
	public static Date max(Date self, Date other) {
		if (self == null || other == null) {
			throw new IllegalArgumentException("Invalid self or other.");
		}
		if (self.compareTo(other) > 0) {
			return self;
		}
		return other;
	}

	/**
	 * 比较日期取靠前的日期
	 * 
	 * @param self
	 *            日期1
	 * @param other
	 *            日期2
	 * @return
	 */
	public static Date min(Date self, Date other) {
		if (self == null || other == null) {
			throw new IllegalArgumentException("Invalid self or other.");
		}
		if (self.compareTo(other) < 0) {
			return self;
		}
		return other;
	}

	/**
	 * 判断 self是否早于other
	 * 
	 * @param self
	 * @param other
	 * @return
	 */
	public static boolean before(Date self, Date other) {
		if (self != null && other != null) {
			return self.compareTo(other) < 0;
		}
		return false;
	}

	/**
	 * 判断self是否晚于other
	 * 
	 * @param self
	 * @param other
	 * @return
	 */
	public static boolean after(Date self, Date other) {
		if (self != null && other != null) {
			return self.compareTo(other) > 0;
		}
		return false;
	}

	/**
	 * 获取指定时段 timeDuration中限电时段limitDuration的限电时长
	 * 
	 * @param timeDuration
	 *            指定时段
	 * @param limitDuration
	 *            限电时段
	 * @return 获取限电时长
	 */
	public static double getLimitTime(TimeDuration timeDuration, TimeDuration limitDuration) {
		if (timeDuration == null || limitDuration == null) {
			throw new IllegalArgumentException("Invalid timeDuration or limitDuration.");
		}
		Date currentDate = Calendar.getInstance(Locale.CHINA).getTime();
		Date maxStartDate = TimeUtil.max(timeDuration.getStartDate(), limitDuration.getStartDate());
		Date limitEndDate = currentDate;
		if (limitDuration != null && limitDuration.getEndDate() != null) {
			limitEndDate = limitDuration.getEndDate();
		}
		Date minEndDate = TimeUtil.min(timeDuration.getEndDate(), limitEndDate);
		if (minEndDate.compareTo(maxStartDate) <= 0) {
			return 0;
		}
		double result = (minEndDate.getTime() - maxStartDate.getTime()) * 1.0 / 1000 * 3600;
		return result;
	}

	/**
	 * 获取指定时段受限电影响的限电时段(时段交集)
	 * 
	 * @param timeDuration
	 *            指定时段
	 * @param limitDuration
	 *            限电时段
	 * @return
	 */
	public static TimeDuration getLimitTimeDuration(TimeDuration timeDuration, TimeDuration limitDuration) {
		if (timeDuration == null || limitDuration == null) {
			throw new IllegalArgumentException("Invalid timeDuration or limitDuration.");
		}
		Date currentDate = Calendar.getInstance(Locale.CHINA).getTime();
		Date maxStartDate = TimeUtil.max(timeDuration.getStartDate(), limitDuration.getStartDate());
		Date limitEndDate = currentDate;
		if (limitDuration != null && limitDuration.getEndDate() != null) {
			limitEndDate = limitDuration.getEndDate();
		}
		Date minEndDate = TimeUtil.min(timeDuration.getEndDate(), limitEndDate);
		if (minEndDate.compareTo(maxStartDate) <= 0) {
			return new TimeDuration(minEndDate, minEndDate);
		}
		return new TimeDuration(maxStartDate, minEndDate);
	}

	/**
	 * 获取指定时段不受限电影响的时段(时段差集)
	 * 
	 * @param timeDuration
	 *            时段
	 * @param limitDuration
	 *            限电时段
	 * @return
	 */
	public static List<TimeDuration> getUnlimitTimeDuration(TimeDuration timeDuration, TimeDuration limitDuration) {
		List<TimeDuration> resList = new ArrayList<TimeDuration>();
		TimeDuration intersection = getLimitTimeDuration(timeDuration, limitDuration);
		if (intersection.zeroDuration()) {
			resList.add(timeDuration);
			return resList;
		}
		Date start = timeDuration.getStartDate();
		Date end = timeDuration.getEndDate();
		Date limitStart = intersection.getStartDate();
		Date limitEnd = intersection.getEndDate();
		List<Date> tmpList = new ArrayList<>();
		tmpList.add(start);
		tmpList.add(end);
		tmpList.add(limitStart);
		tmpList.add(limitEnd);
		Collections.sort(tmpList, new DateComparator());
		TimeDuration duration1 = new TimeDuration(tmpList.get(0), tmpList.get(1));
		TimeDuration duration2 = new TimeDuration(tmpList.get(1), tmpList.get(2));
		TimeDuration duration3 = new TimeDuration(tmpList.get(2), tmpList.get(3));
		resList.add(duration1);
		resList.add(duration2);
		resList.add(duration3);
		resList.remove(intersection);
		return resList;
	}

	/**
	 * 获取指定时段受限电影响的时段(时段交集)
	 * 
	 * @param timeDuration
	 *            统计时段
	 * @param limitDurationSet
	 *            限电时段集合
	 * @return
	 */
	public static Set<TimeDuration> getLimitTimeDuration(TimeDuration timeDuration,
                                                                                   Set<TimeDuration> limitDurationSet) {
		Set<TimeDuration> realLimitDurationSet = new HashSet<>();
		for (TimeDuration duration : limitDurationSet) {
			TimeDuration realLimit = getLimitTimeDuration(timeDuration, duration);
			realLimitDurationSet.add(realLimit);
		}
		return realLimitDurationSet;
	}

	/**
	 * 获取指定时段不受限电影响的时段(时段差集)
	 * 
	 * @param timeDuration
	 *            统计时段
	 * @param limitDurationSet
	 *            限电时段集合
	 * @return
	 */
	public static Set<TimeDuration> getUnlimitTimeDuration(TimeDuration timeDuration,
                                                                                     Set<TimeDuration> limitDurationSet) {
		Set<TimeDuration> realLimitDurationSet = new HashSet<>();
		for (TimeDuration duration : limitDurationSet) {
			TimeDuration realLimit = getLimitTimeDuration(timeDuration, duration);
			realLimitDurationSet.add(realLimit);
		}
		Set<TimeDuration> durationSet = new HashSet<TimeDuration>();
		Set<Date> dateSet = new TreeSet<Date>();
		for (TimeDuration duration : realLimitDurationSet) {
			dateSet.add(duration.getStartDate());
			dateSet.add(duration.getEndDate());
		}
		dateSet.add(timeDuration.getStartDate());
		dateSet.add(timeDuration.getEndDate());
		List<Date> dateList = new ArrayList<>(dateSet);
		for (int idx = 0; idx < dateList.size() - 1; idx++) {
			TimeDuration duration = new TimeDuration(dateList.get(idx), dateList.get(idx + 1));
			durationSet.add(duration);
		}
		durationSet.removeAll(realLimitDurationSet);
		return durationSet;
	}

	public static class DateComparator implements Comparator<Date> {
		public int compare(Date self, Date other) {
			return self.compareTo(other);
		}
	}

	/**
	 * 将时间段按 15分钟切分
	 * 
	 * @param startDate
	 *            起始时间
	 * @param endDate
	 *            截止时间
	 * @return
	 */
	public static List<TimeDuration> splitDuration5min(Date startDate, Date endDate) {
		List<TimeDuration> list = new ArrayList<TimeDuration>();
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(startDate);
		while (calendar.getTime().getTime() < endDate.getTime()) {
			Date start = calendar.getTime();
			calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) + DEFAULT_INTERVAL_MINUTES);
			Date end = calendar.getTime();
			TimeDuration duration = new TimeDuration(start, end);
			if (!duration.zeroDuration()) {
				list.add(duration);
			}
		}
		if (CollectionUtils.isNotEmpty(list)) {
			TimeDuration duration = list.get(list.size() - 1);
			while (CollectionUtils.isNotEmpty(list) && duration.getEndDate().getTime() > endDate.getTime()) {
				list.remove(list.get(list.size() - 1));
				duration = list.get(list.size() - 1);
			}
			TimeDuration last = new TimeDuration(duration.getEndDate(), endDate);
			list.add(last);
		}
		return list;
	}

	public static Set<String> getDurationDays(TimeDuration duration) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		Set<String> days = new TreeSet<String>();
		Date startDate = duration.getStartDate();
		Date endDate = duration.getEndDate();
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(startDate);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		while (calendar.getTime().compareTo(endDate) < 0) {
			days.add(dateFormat.format(calendar.getTime()));
			int date = calendar.get(Calendar.DAY_OF_MONTH);
			date++;
			calendar.set(Calendar.DAY_OF_MONTH, date);
		}
		return days;
	}

	/**
	 * 按指定时间单位的间隔对给定时段进行拆分
	 * 
	 * @param duration
	 * @param interval
	 * @param timeUnit
	 * @return
	 */
	public static List<TimeDuration> splitDurationByInterval(TimeDuration specialDuration, int interval,
                                                                                       TimeUnit timeUnit) {
		List<TimeDuration> list = new ArrayList<TimeDuration>();
		Date startDate = specialDuration.getStartDate();
		Date endDate = specialDuration.getEndDate();
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.setTime(startDate);
		while (calendar.getTime().getTime() < endDate.getTime()) {
			Date start = calendar.getTime();
			if (TimeUnit.MINUTES.equals(timeUnit)) {
				calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) + interval);
			} else if (TimeUnit.HOURS.equals(timeUnit)) {
				calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) + interval);
			} else if (TimeUnit.DAYS.equals(timeUnit)) {
				calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) + interval);
			} else {
				calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) + interval);
			}
			Date end = calendar.getTime();
			TimeDuration duration = new TimeDuration(start, end);
			if (!duration.zeroDuration()) {
				list.add(duration);
			}
		}
		if (CollectionUtils.isNotEmpty(list)) {
			TimeDuration duration = list.get(list.size() - 1);
			while (CollectionUtils.isNotEmpty(list) && duration.getEndDate().getTime() > endDate.getTime()) {
				list.remove(list.get(list.size() - 1));
				duration = list.get(list.size() - 1);
			}
			TimeDuration last = new TimeDuration(duration.getEndDate(), endDate);
			list.add(last);
		}
		return list;
	}

	/**
	 * 将specialDuration按日期拆分时段
	 * 
	 * @param specialDuration
	 *            指定时段
	 * @return
	 */
	public static List<TimeDuration> splitDurationByDay(TimeDuration specialDuration) {
		List<TimeDuration> resList = new ArrayList<TimeDuration>();
		Set<String> days = TimeUtil.getDurationDays(specialDuration);
		if (CollectionUtils.size(days) == 1) {
			resList.add(specialDuration);
			return resList;
		}
		Calendar startCalendar = Calendar.getInstance(Locale.CHINA);
		startCalendar.setTime(specialDuration.getStartDate());
		for (int idx = 0; idx < days.size(); idx++) {
			if (idx == 0) {
				startCalendar.set(Calendar.HOUR_OF_DAY, 23);
				startCalendar.set(Calendar.MINUTE, 59);
				startCalendar.set(Calendar.SECOND, 59);
				TimeDuration duration = new TimeDuration(specialDuration.getStartDate(), startCalendar.getTime());
				resList.add(duration);
			} else if (idx == CollectionUtils.size(days) - 1) {
				Calendar endCalendar = Calendar.getInstance(Locale.CHINA);
				endCalendar.setTime(specialDuration.getEndDate());
				endCalendar.set(Calendar.HOUR_OF_DAY, 0);
				endCalendar.set(Calendar.MINUTE, 0);
				endCalendar.set(Calendar.SECOND, 0);
				TimeDuration duration = new TimeDuration(endCalendar.getTime(), specialDuration.getEndDate());
				resList.add(duration);
			} else {
				startCalendar.set(Calendar.DAY_OF_MONTH, startCalendar.get(Calendar.DAY_OF_MONTH) + 1);
				startCalendar.set(Calendar.HOUR_OF_DAY, 0);
				startCalendar.set(Calendar.MINUTE, 0);
				startCalendar.set(Calendar.SECOND, 0);
				Date start = startCalendar.getTime();
				startCalendar.set(Calendar.HOUR_OF_DAY, 23);
				startCalendar.set(Calendar.MINUTE, 59);
				startCalendar.set(Calendar.SECOND, 59);
				Date end = startCalendar.getTime();
				resList.add(new TimeDuration(start, end));
			}
		}
		return resList;
	}

	private static String formatHHmmss(String time) {
		Time timeInfo = Time.parseTime(time);
		if (timeInfo != null) {
			return timeInfo.toString();
		}
		return time;
	}

	/**
	 * 将指定时段timeDuration 按 起始时间starTime 到 结束时间endTime进行拆分
	 * 
	 * @param timeDuration
	 * @param startTime
	 * @param endTime
	 * @return
	 */
	public static List<TimeDuration> splitDurationByTimeStage(TimeDuration timeDuration, String startTime,
                                                                                        String endTime) {
		List<TimeDuration> resList = new ArrayList<>();
		startTime = StringUtils.defaultIfBlank(startTime, DEFAULT_START_TIME);
		endTime = StringUtils.defaultIfBlank(endTime, DEFAULT_END_TIME);
		startTime = formatHHmmss(startTime);
		endTime = formatHHmmss(endTime);
		List<TimeDuration> dayDurations = TimeUtil.splitDurationByDay(timeDuration);
		if (CollectionUtils.isNotEmpty(dayDurations)) {
			for (TimeDuration duration : dayDurations) {
				Date start = duration.getStartDate();
				Date end = duration.getEndDate();
				Date startDate = TimeUtil.parseTime(
						String.format("%s %s", TimeUtil.format(start, "yyyy-MM-dd"), startTime), "yyyy-MM-dd HH:mm:ss");
				Date endDate = TimeUtil.parseTime(String.format("%s %s", TimeUtil.format(end, "yyyy-MM-dd"), endTime),
						"yyyy-MM-dd HH:mm:ss");
				Date maxStartDate = TimeUtil.max(start, startDate);
				Date minEndDate = TimeUtil.min(end, endDate);
				resList.add(new TimeDuration(maxStartDate, minEndDate));
			}
		}
		return resList;
	}

	public static Integer getDurationIndex(Date date, List<TimeDuration> durationList) {
		AtomicInteger atomicInteger = new AtomicInteger(0);
		for (TimeDuration timeDuration : durationList) {
			int idx = atomicInteger.incrementAndGet();
			if (timeDuration.inDuration(date.getTime())) {
				return idx;
			}
		}
		return -1;
	}

	public static int getStageIndexOfDay(Date currentDate, int interval, TimeUnit timeUnit) {
		Date startDate = TimeUtil.getStartTimeOfDay(currentDate);
		Date endDate = TimeUtil.getEndTimeOfDay(currentDate);
		TimeDuration specialDuration = new TimeDuration(startDate, endDate);
		List<TimeDuration> durationList = TimeUtil.splitDurationByInterval(specialDuration, interval, timeUnit);
		Integer stageIndex = TimeUtil.getDurationIndex(currentDate, durationList);
		return stageIndex;
	}

	/**
	 * 判断当前时段是否与指定时段相连(可以合并)
	 * 
	 * @param timeDuration
	 * @return
	 */
	public static boolean canBeMerge(TimeDuration prevDuration, TimeDuration nextDuration) {
		boolean merge = (prevDuration.getEndDate() == nextDuration.getStartDate());
		return merge;
	}

	/**
	 * 判断指定时间是否在时段内
	 * 
	 * @param duration
	 * @param date
	 * @return
	 */
	public static boolean isInDuration(TimeDuration duration, Date date) {
		if (duration != null && duration.isValidDuration() && date != null) {
			boolean flag = duration.inDuration(date.getTime());
			return flag;
		}
		return false;
	}

	/**
	 * 判断指定时段是否与统计时段有交集
	 * 
	 * @param statisticDuration
	 *            统计时段
	 * @param specialDuration
	 *            指定时段
	 * @return
	 */
	public static boolean isIntersectionDuration(TimeDuration statisticDuration, TimeDuration specialDuration) {
		boolean contains = statisticDuration.contains(specialDuration);
		boolean crossEnd = statisticDuration.containsEndWith(specialDuration);
		boolean crossStart = statisticDuration.containsStartWith(specialDuration);
		boolean result = contains || crossEnd || crossStart;
		return result;
	}

	/**
	 * 取两个时段交集
	 * 
	 * @param statisticDuration
	 * @param specialDuration
	 * @return
	 */
	public static TimeDuration intersectionDuration(TimeDuration statisticDuration, TimeDuration specialDuration) {
		Date start = TimeUtil.max(statisticDuration.getStartDate(), specialDuration.getStartDate());
		Date end = TimeUtil.min(statisticDuration.getEndDate(), specialDuration.getEndDate());
		if (start.compareTo(end) < 0) {
			return new TimeDuration(start, end);
		}
		return null;
	}

	/**
	 * 对指定时段集合进行过滤, 保留时间点在 startTime~endTime之内的时段
	 * 
	 * @param durationList
	 *            时段集合(每个时段均为单个日期的时段)
	 * @param startTime
	 *            起始时间(yyyy-MM-dd'T'HH:mm:ss'Z'或 HH:mm:ss)
	 * @param endTime
	 *            截止时间(yyyy-MM-dd'T'HH:mm:ss'Z'或 HH:mm:ss)
	 * @return
	 */
	public static List<TimeDuration> filterByTime(List<TimeDuration> durationList, Time startTime, Time endTime) {
		durationList = Optional.ofNullable(durationList).orElse(Collections.EMPTY_LIST);
		List<TimeDuration> resList = new ArrayList<TimeDuration>();
		for (TimeDuration timeDuration : durationList) {
			Date startDate = timeDuration.getStartDate();
			Date endDate = timeDuration.getEndDate();

			Date sStart = startTime.getTimeDate(startDate);
			Date sEnd = endTime.getTimeDate(startDate);

			Date start = TimeUtil.max(startDate, sStart);
			Date end = TimeUtil.min(endDate, sEnd);
			resList.add(new TimeDuration(start, end));
		}
		return resList;
	}

	/**
	 * 将specialDuration拆分为同一天的多个时段后, 只保留startTime~endTime之内的时段
	 * 
	 * @param startTime
	 *            起始时间
	 * @param endTime
	 *            截止时间
	 * @param specialDuration
	 *            统计时段
	 * @return
	 */
	public static List<TimeDuration> filterDuration(Time startTime, Time endTime, TimeDuration specialDuration) {
		List<TimeDuration> resList = new ArrayList<TimeDuration>();
		if (startTime == null || endTime == null) {
			resList.add(specialDuration);
			return resList;
		}
		List<TimeDuration> splitList = TimeUtil.splitDurationByDay(specialDuration);
		resList = filterByTime(splitList, startTime, endTime);
		return resList;
	}

	public static boolean sameYear(Date self, Date other) {
		boolean same = (self != null && other != null) && (self.getYear() == other.getYear());
		return same;
	}

	public static boolean sameMonth(Date self, Date other) {
		boolean same = (self != null && other != null)
				&& (self.getYear() == other.getYear() && self.getMonth() == other.getMonth());
		return same;
	}

	public static boolean sameDate(Date start, Date end) {
		boolean same = ((start != null && end != null) && start.getDate() == end.getDate()
				&& start.getMonth() == end.getMonth() && start.getYear() == end.getYear());
		return same;
	}

	/**
	 * 获取当月的天数
	 * 
	 * @param date
	 * @return
	 */
	public static int getDaysOfMonth(Date date) {
		String dateStr = TimeUtil.format(date, "yyyy-MM-dd");
		date = TimeUtil.parseDate(dateStr);
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
	}

	public static void main(String[] args) {
		Date date = Calendar.getInstance(Locale.CHINA).getTime();

		System.out.println(TimeUtil.getTimeDurationPerMonth(date));
		System.out.println(TimeUtil.getTimeDurationPerQuarter(date));
		System.out.println(TimeUtil.parseTime("2021-01-01T16:00:00.000Z", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
		System.out.println(TimeUtil.formatHHmm("12:00"));
		System.out.println(TimeUtil.getMonthsOfQuarters(date, "yyyy-MM"));

		System.out.println(TimeUtil.format(TimeUtil.getYesterday(), "yyyy-MM-dd HH:mm:ss"));
		System.out.println(TimeUtil.format(TimeUtil.getYesterday(23, 59, 59), "yyyy-MM-dd HH:mm:ss"));
		System.out.println("==========================================================");
		System.out.println(TimeUtil.getStatisticStartTime(date, EnumTimeUnit.MINUTES));
		System.out.println(TimeUtil.getStatisticStartTime(date, EnumTimeUnit.HOURS));
		System.out.println(TimeUtil.getStatisticStartTime(date, EnumTimeUnit.DAYS));
		System.out.println(TimeUtil.getStatisticStartTime(date, EnumTimeUnit.WEEKS));
		System.out.println(TimeUtil.getStatisticStartTime(date, EnumTimeUnit.MONTHS));
		System.out.println(TimeUtil.getStatisticStartTime(date, EnumTimeUnit.QUARTER));
		System.out.println(TimeUtil.getStatisticStartTime(date, EnumTimeUnit.YEARS));
		System.out.println("==========================================================");
		System.out.println(TimeUtil.getStatisticEndTime(date, EnumTimeUnit.MINUTES));
		System.out.println(TimeUtil.getStatisticEndTime(date, EnumTimeUnit.HOURS));
		System.out.println(TimeUtil.getStatisticEndTime(date, EnumTimeUnit.DAYS));
		System.out.println(TimeUtil.getStatisticEndTime(date, EnumTimeUnit.WEEKS));
		System.out.println(TimeUtil.getStatisticEndTime(date, EnumTimeUnit.MONTHS));
		System.out.println(TimeUtil.getStatisticEndTime(date, EnumTimeUnit.QUARTER));
		System.out.println(TimeUtil.getStatisticEndTime(date, EnumTimeUnit.YEARS));
		System.out.println("==========================================================");
		System.out.println(TimeUtil.getStartTimeOfHour(TimeUtil.parseTime("2020-12-15T12:00:00Z")));
		System.out.println(TimeUtil.getEndTimeOfHour(TimeUtil.parseTime("2020-12-15T12:00:00Z")));
	}
}
